package com.gonsin.gview.logic.services;

import com.gonsin.gview.annotations.GContext;
import com.gonsin.gview.annotations.interfaces.*;
import com.gonsin.gview.logic.config.GViewGlobalEnumsService;
import com.gonsin.gview.logic.exceptions.BaseGViewException;
import com.gonsin.gview.logic.model.DataPo;
import com.gonsin.gview.logic.model.DataRequest;
import com.gonsin.gview.logic.services.data.GDataManager;
import com.gonsin.gview.logic.utils.SpringUtil;
import com.gonsin.i18n.logic.T;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Order
@Service
public class GViewDataServiceImpl implements InitializingBean {

    @Autowired private GViewClientServiceImpl clientService;
    @Autowired private GViewGlobalEnumsService enumsService;

    private Map<String, GDataManager> dataManagerMap = new HashMap<>(); // key = dataId， value = GDataManager

    private Map<String, Set<String>> dataIdMap = new HashMap<>();       // key = dataSource， value = dataId列表


    /**
     * 根据dataId查询 GDataManager，校验数据是否正确
     */
    public GDataManager findDataManagerById(String dataId){
        return dataManagerMap.get(dataId);
    }


    /**
     * 获取数据
     */
    public Object getData(HttpServletRequest request, HttpServletResponse response, DataRequest dataRequest) throws Throwable {
        String dataId = dataRequest.getDataId();
        if(StringUtils.isEmpty(dataId)){
            throw new BaseGViewException("dataId"+T.t("不能为空"));
        }
        GDataManager manager = dataManagerMap.get(dataId);
        if(manager == null){
            throw new BaseGViewException(String.format(T.t("找不到该数据源【%s】"), dataId));
        }
        return manager.generalData(request, response, dataRequest);
    }


    /**
     * 准备sql的查询数据
     */
    public void readySqlData(GContext context, String dataId, String sql) {
        dataManagerMap.put(dataId, GDataManager.initForSql(context, dataId, sql));
    }


    /**
     * 准备sql的查询数据
     */
    public void readySingleSqlData(GContext context, String dataId, String sql) {
        dataManagerMap.put(dataId, GDataManager.initForSingleSql(context, dataId, sql));
    }

    /**
     * 准备动态加载class的数据
     */
    public void readyData(GContext context, String dataId, Class<? extends IDataPicker> clazz) {
        IDataPicker picker = SpringUtil.getBean(clazz);
        if(picker == null){
            try {
                picker = clazz.newInstance();
            } catch (Exception e) {
                log.error(e.toString(), e);
//                throw new CreateActionException(clazz.getName());
                throw new BaseGViewException(String.format("无法创建类【%s】", clazz.getName()));
            }
        }
        dataManagerMap.put(dataId, GDataManager.initForPicker(context, dataId, picker));
    }

    /**
     * 准备动态加载class的数据
     */
    public void readyData(GContext context, String dataId, IDataPicker picker) {
        dataManagerMap.put(dataId, GDataManager.initForPicker(context, dataId, picker));
    }

    /**
     * 准备静态的json数据
     */
    public void readyJsonData(GContext context, String dataId, String json, String titleName) {
        dataManagerMap.put(dataId, GDataManager.initForJson(context, dataId, json, titleName));
    }

    /**
     * 准备列表数据
     */
    public void readyListData(GContext context, String dataId, Class<? extends IListDataPicker> clazz) {
        IListDataPicker picker = SpringUtil.getBean(clazz);
        if(picker == null){
            try {
                picker = clazz.newInstance();
            } catch (Exception e) {
                log.error(e.toString(), e);
//                throw new CreateActionException(clazz.getName());
                throw new BaseGViewException(String.format("无法创建类【%s】", clazz.getName()));
            }
        }
        dataManagerMap.put(dataId, GDataManager.initForListDataPicker(context, dataId, picker));
    }

    /**
     * 准备表格数据
     */
    public void readyTableData(GContext context, String dataId, Class<? extends ITableDataPicker> clazz) {
        ITableDataPicker picker = SpringUtil.getBean(clazz);
        if(picker == null){
            try {
                picker = clazz.newInstance();
            } catch (Exception e) {
                log.error(e.toString(), e);
//                throw new CreateActionException(clazz.getName());
                throw new BaseGViewException(String.format("无法创建类【%s】", clazz.getName()));
            }
        }
        dataManagerMap.put(dataId, GDataManager.initForTableDataPicker(context, dataId, picker));
    }

    /**
     * 准备表格数据
     */
    public void readyTableDataByPicker(GContext context, String dataId, ITableDataPicker picker) {
        dataManagerMap.put(dataId, GDataManager.initForTableDataPicker(context, dataId, picker));

        Set<String> dataIds = dataIdMap.computeIfAbsent(picker.getClass().getSimpleName(), k -> new HashSet<>());
        dataIds.add(dataId);
    }

//    /**
//     * 为树状数据做准备
//     */
//    public void readyTreeData(GContext context, String dataId, Class<? extends ITreeDataPicker> clazz) {
//        ITreeDataPicker picker = SpringUtil.getBean(clazz);
//        if(picker == null){
//            try {
//                picker = clazz.newInstance();
//            } catch (Exception e) {
//                log.error(e.toString(), e);
////                throw new CreateActionException(clazz.getName());
//                throw new BaseGViewException(String.format("无法创建类【%s】", clazz.getName()));
//            }
//        }
//        dataManagerMap.put(dataId, GDataManager.initForTreeDataPicker(context, dataId, picker));
//    }

    /**
     * 准备数据源
     */
    public void readyTableDataSource(GContext context, String dataId, Class sourceService, Method sourceMethod, String dataSource) {
        Object obj = SpringUtil.getBean(sourceService);
        if(obj == null){
//            throw new ActionClassNotFoundException(context, actionService.getName());
            throw new BaseGViewException(String.format("【%s】绑定了不存在的class【%s】",
                    context.getViewName(), sourceService.getName()));
        }
        Set<String> dataIds = dataIdMap.computeIfAbsent(dataSource, k -> new HashSet<>());
        dataIds.add(dataId);
        dataManagerMap.put(dataId, GDataManager.initForTableDataDelegate(context, dataId, obj, sourceMethod));
    }

    /**
     * 准备List格式的数据源
     */
    public void readyListDataSource(GContext context, String dataId, Class sourceService, Method sourceMethod, String dataSource) {
        Object obj = SpringUtil.getBean(sourceService);
        if(obj == null){
//            throw new ActionClassNotFoundException(context, actionService.getName());
            throw new BaseGViewException(String.format("【%s】绑定了不存在的class【%s】",
                    context.getViewName(), sourceService.getName()));
        }
        Set<String> dataIds = dataIdMap.computeIfAbsent(dataSource, k -> new HashSet<>());
        dataIds.add(dataId);
        dataManagerMap.put(dataId, GDataManager.initForListDataDelegate(context, dataId, obj, sourceMethod));
    }

    /**
     * 准备List格式的数据源
     */
    public void readySingleDataSource(GContext context, String dataId, Class sourceService, Method sourceMethod, String dataSource) {
        Object obj = SpringUtil.getBean(sourceService);
        if(obj == null){
//            throw new ActionClassNotFoundException(context, actionService.getName());
            throw new BaseGViewException(String.format("【%s】绑定了不存在的class【%s】",
                    context.getViewName(), sourceService.getName()));
        }
        Set<String> dataIds = dataIdMap.computeIfAbsent(dataSource, k -> new HashSet<>());
        dataIds.add(dataId);
        dataManagerMap.put(dataId, GDataManager.initForSingleDataDelegate(context, dataId, obj, sourceMethod));
    }

    /**
     * 获取所有数据
     */
    public List<DataPo> getAllData() {
        return dataManagerMap.keySet().stream().map(m -> {
            DataPo d = new DataPo();
            d.setDataId(m);
            d.setMetaData(dataManagerMap.get(m).getMetaData());
            d.setDataManagerType(dataManagerMap.get(m).getDataManagerType());
            d.setMethodName(dataManagerMap.get(m).toString());
            return d;
        }).collect(Collectors.toList());
    }

    /**
     * 通知数据源有更新
     */
    public void notifyDataSourceChanged(String edificeKey, String dataSource) {
        Set<String> dataIds = dataIdMap.get(dataSource);
        if(!CollectionUtils.isEmpty(dataIds)){
            for(String dataId: dataIds){
                clientService.notifyDataChanged(edificeKey, dataId);
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
//        ConvertUtils.register(new MyDateConverter(), java.util.Date.class);
    }

    /**
     * 初始化枚举数据
     */
    public void readyEnumsData(GContext context, String dataId, String enumName) {
        dataManagerMap.put(dataId, GDataManager.initForEnums(context, dataId, enumsService.getEnums(enumName)));
        Set<String> dataIds = dataIdMap.computeIfAbsent(enumName, k -> new HashSet<>());
        dataIds.add(dataId);
    }

    /**
     * 通过dataSource找到dataId
     */
    public String findDataIdBySource(String dataSource) {
        Set<String> dataIds = dataIdMap.get(dataSource);
        if(dataIds == null || dataIds.isEmpty()){
            return null;
        }
        return dataIds.stream().findFirst().orElse(null);
    }
}
